﻿using System;
using System.Collections.Generic;
using System.Linq;
using HQPad.DAL;
using HQPad.Models;

namespace HQPad.Services
{
    /// <summary>
    /// List of all possible types of bonus.
    /// These names are stored as text against the bonus
    /// so we can extend it.
    /// </summary>
    public enum BonusTypes
    {
        ArmouredDex,
        UnarmouredDex,
        PhysicalAC,
        MagicalAC,
        PowerAC,
        LifeRank,
        SpellLevel,
        Invocations1to8,
        Invocations9,
        Invocations10,
        Spells1to8,
        Spells9,
        Spells10,
        PowerRank,
        PsiRank,
        AdrenalRank,
        KiRank,
        DisarmUse,
        KnockbackUse,
        KnockdownUse,
        StunUse,
        StunShotUse,
        AllowTertiaryGuild,     // allows use of tertiary guild regardless of primary and secondary.
        AllowSkill,             // allows the specific use of any one skill regardless of requirements.
        MaxSkillRanks,          // allows extra skill ranks. Value should be skill slug. Quantity the number of extra ranks.
        SchoolAccessMage,       // allows mage level access to a school of magic.
        SchoolAccessWizard,     // allows wizard level access to a school of magic.
        SchoolAccessSorceror,   // allows sorceror level access to a school of magic.
        SchoolAccessSpecialist, // allows access to a school of magic specialist spell.
        SchoolAccessPrimary,    // allows access to a school of magic primary spells.
        SectAccessLay,          // allows lay level access to a power sect.
        SectAccessPriest,       // allows priest level access to a power sect.
        SectAccessHighPriest    // allows high priest level access to a power sect.
    }

    public enum BonusRequirement
    {
        None,              // No requirement.
        EquippedArmour     // a suit of armour must be equipped.
    }

    public interface IBonusService
    {
        Bonus CreateBonus(int? parentSkillId, BonusTypes type, int quantity, string value, BonusRequirement requirement);
        IEnumerable<Bonus> GetSkillBonuses(int skillID);
        IEnumerable<SkillBonus> GetSkillBonuses(int ruleSetId, IEnumerable<string> skillSlugs);
        void DeleteBonus(int bonusId);
    }

    public class BonusService : IBonusService
    {
        private HQContext context = null;

        public BonusService(IUnitOfWork context)
        {
            this.context = (HQContext)context;
        }

        #region CreateBonus
        /// <summary>Create a new bonus object.</summary>
        /// <param name="parentSkillId">The source skill if applicable.</param>
        /// <param name="type">The type of bonus granted.</param>
        /// <param name="quantity">The quantity granted.</param>
        /// <param name="value">An optional bonus value.</param>
        /// <returns>A new bonus object.</returns>
        public Bonus CreateBonus(int? parentSkillId, BonusTypes type, int quantity, string value, BonusRequirement requirement)
        {
            Bonus bonus = new Bonus()
            {
                Type = Enum.GetName(typeof(BonusTypes), type),
                Value = value,
                Quantity = quantity,
                Requirement = (requirement != BonusRequirement.None) ? Enum.GetName(typeof(BonusRequirement), requirement) : string.Empty
            };

            if (parentSkillId.HasValue)
                bonus.SkillID = parentSkillId.Value;

            context.Bonuses.Add(bonus);

            return bonus;
        }
        #endregion

        #region GetSkillBonuses
        /// <summary>Find the bonuses for a skill.</summary>
        /// <param name="skillID">The bonus parent skill id.</param>
        /// <returns>All bonuses attached to the skill..</returns>
        public IEnumerable<Bonus> GetSkillBonuses(int skillID)
        {
            return this.context.Bonuses.Include("Skill")
                .Where(b => b.SkillID == skillID);
        }

        /// <summary>
        /// Get all bonuses from skills with slugs from a given set.
        /// </summary>
        /// <param name="ruleSetId">A rule set id.</param>
        /// <param name="skillSlugs">A list of skill slugs.</param>
        /// <returns>All bonuses attached to all skills in the skill slug set.</returns>
        public IEnumerable<SkillBonus> GetSkillBonuses(int ruleSetId, IEnumerable<string> skillSlugs)
        {
            return (from b in context.Bonuses.Include("Skill")
                    join s in context.Skills on b.SkillID equals s.SkillID
                    where skillSlugs.Contains(s.Slug) && s.RuleSetID == ruleSetId
                    select new SkillBonus() { Bonus = b, SkillSlug = s.Slug });
                
        }
        #endregion

        #region DeleteBonus
        /// <summary>Delete a bonus.</summary>
        /// <param name="bonusId">The unique id of the bonus.</param>
        public void DeleteBonus(int bonusId)
        {
            Bonus bonus = this.context.Bonuses.Find(bonusId);

            if (bonus != null)
                this.context.Entry<Bonus>(bonus).State = System.Data.EntityState.Deleted;
        }
        #endregion
    }

    public class SkillBonus
    {
        public Bonus Bonus { get; set; }
        public string SkillSlug { get; set; }
    }
}